from decimal import Decimal

import time
from django.db import transaction
from django.utils import timezone
from rest_framework import serializers
from goods.models import SKU
from .models import OrderInfo, OrderGoods
from django_redis import get_redis_connection
import logging


logger = logging.getLogger('django')
class CartSKUSerializer(serializers.ModelSerializer):
    """获取购物车勾选商品到结算页面的序列化器"""
    count = serializers.IntegerField(label='商品数量', min_value=1)

    class Meta:
        model = SKU
        fields = ('id', 'name', 'price', 'default_image_url', 'count')


class SaveOrderSerializer(serializers.ModelSerializer):
    """保存订单信息到表创建对象的序列化器"""
    class Meta:
        model = OrderInfo
        fields = ('order_id', 'address', 'pay_method')
        read_only_fields = ('order_id',)
        extra_kwargs = {
            'address': {
                'write_only': True,
                'required': True
            },
            'pay_method': {
                'write_only': True,
                'required': True
            }
        }

    def create(self, validated_data):
        """保存订单"""
        # 获取当前用户
        user = self.context['request'].user
        address = validated_data['address']
        pay_method = validated_data['pay_method']
        # 查询redis数据库
        redis_conn = get_redis_connection('cart')
        # 获取哈希数据
        redis_cart = redis_conn.hgetall('cart_%s' % user.id)
        # 获取集合数据
        redis_selected = redis_conn.smembers('cart_selected_%s' % user.id)
        # 构造勾选商品的字典
        cart = {}
        for sku_id in redis_selected:
            cart[int(sku_id)] = int(redis_cart[sku_id])
        # cart = {
        #   sku_id: count
        # 。。。。
        # }
        if not cart:
            raise serializers.ValidationError('没有要结算的商品')
        with transaction.atomic():
            # 创建一个保存点
            save_id = transaction.savepoint()
            try:
                # 自己生成一个订单编号
                order_id = timezone.now().strftime('%Y%m%d%H%M%S') + ("%09d" % user.id)
                order_obj = OrderInfo.objects.create(
                    order_id=order_id,
                    user=user,
                    address=address,
                    pay_method=pay_method,
                    total_count=0,
                    total_amount=Decimal('0.00'),
                    freight=Decimal('10.00'),
                    status=OrderInfo.ORDER_STATUS_ENUM["UNSEND"] if pay_method==OrderInfo.PAY_METHODS_ENUM['CASH'] else
                    OrderInfo.ORDER_STATUS_ENUM["UNPAID"]
                )
                # 判断商品的库存
                for sku_id, count in cart.items():
                    while True:
                        sku = SKU.objects.get(id=sku_id)
                        origin_count = sku.stock
                        origin_sales = sku.sales
                        if origin_count < count:
                            # 抛出异常之前进行回滚
                            transaction.savepoint_rollback(save_id)
                            raise serializers.ValidationError('库存不足')
                        # time.sleep(5)

                        new_count = origin_count-count
                        new_sales = origin_sales+count
                        # update返回受影响的行数
                        result = SKU.objects.filter(id=sku_id, stock=origin_count).update(stock=new_count, sales=new_sales)
                        # sku.save()
                        if result == 0:
                            continue
                        order_obj.total_count += count
                        order_obj.total_amount += (sku.price * count)
                        order_obj.save()
                        OrderGoods.objects.create(
                            order=order_obj,
                            sku=sku,
                            count=count,
                            price=sku.price
                        )
                    # 结束这个商品的处理，跳到另一个sku，也就是外面的for循环
                        break

            except Exception as e:
                logger.error(e)
                # 捕获到异常回滚到保存点
                transaction.savepoint_rollback(save_id)
                raise
            # 没有异常一起提交
            else:
                transaction.savepoint_commit(save_id)
        # 删除购物车数据
        pl = redis_conn.pipeline()
        pl.hdel('cart_%s' % user.id, *redis_selected)
        pl.srem('cart_selected_%s' % user.id, *redis_selected)
        pl.execute()
        # 返回订单对象
        return order_obj
